import {AxdrType} from "./AxdrType";
import {Buffer} from "buffer";
import {ReverseByteArrayOutputStream} from "../ReverseByteArrayOutputStream";
import {ReverseByteArrayInputStream} from "../ReverseByteArrayInputStream";

export class AxdrLength implements AxdrType {

    length: number;

    constructor(length: number) {
        this.length = length
    }

    static encodeLength(output: ReverseByteArrayOutputStream, length: number): number {
        let codeLength = 0;
        if (length == 0) {
            output.write(0);
            codeLength++;
        } else {
            let lengthOfLength = 0;
            for (let i = 0; (length >> 8 * (i)) != 0; i++) {
                output.write((length >> 8 * (i)) & 0xff)
                lengthOfLength++;
                codeLength++;
            }
            if (length >= 128) {
                output.write(((lengthOfLength & 0xff) | 0x80));
                codeLength++;
            }
        }
        return codeLength;
    }

    encodeLengthBuf(length: number): Buffer {

        if (length == 0) {
            return Buffer.from([0]);
        } else {
            let lengthOfLength = 1;
            while ((length >> (8 * lengthOfLength)) != 0) {
                lengthOfLength++;
            }
            let offset = 0;

            var buffer: Buffer

            if (length > 255) {
                buffer = Buffer.alloc(lengthOfLength + 1)
                buffer[0] = lengthOfLength | 0x80;
                offset++;
            } else {
                buffer = Buffer.alloc(lengthOfLength)
            }
            for (let i = 0; i < lengthOfLength; i++) {
                buffer[offset + i] = (length >> (8 * (lengthOfLength - 1 - i)))
            }
        }
        return buffer
    }

    decode(input: ReverseByteArrayInputStream): number {
        let codeLength = 0;
        this.length = input.read();
        codeLength++;
        if ((this.length & 0x80) == 0x80) {
            let encodedLength = this.length ^ 0x80;
            codeLength += encodedLength;
            this.length = 0;
            let byteCode = Buffer.alloc(encodedLength);
            if (input.readoffset(byteCode, 0, encodedLength) < encodedLength) {
                throw new Error("Error Decoding AxdrLength");
            }
            for (let i = 0; i < encodedLength; i++) {
                this.length |= (byteCode[i] & 0xff) << (8 * (encodedLength - i - 1));
            }
        }
        return codeLength;
    }

    getValue(): number {
        return this.length
    }

    encode(output: ReverseByteArrayOutputStream): number {
        return AxdrLength.encodeLength(output, this.length);
    }

}

